from typing import List



"""
CRC32计算 (兼容Java/TypeScript/Python)
Author by: Seraph

from lib import CompatibleCRC32 as CRC32
testCode:str = "This is a Test!!";
crc:int = CRC32.get32BitDec(testCode)
print("crc: "  + str(crc))
testCode:str = "这是个测试Hash的例子";
crc:int = CRC32.get32BitDec(testCode)
print("crc: "  + str(crc))
testCode:str = "This is a 例子!!";
crc:int = CRC32.get32BitDec(testCode)
print("crc: "  + str(crc))
scrc:str = CRC32.get32BitHex(testCode)
print(scrc)
"""

INT_MAX: int = 2147483647
HEX_MAP: List[str] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']

class CompatibleCRC32Data():
    CN: int = 0x04C11DB7
    PTI_TABLE: List[int] = [] #[0] * 256
    """
    CRC32 = X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 + X9 + X8 + X7 + X5 + X4 + X2 + X1 + X0
    """

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls, *args, **kwargs)
            cls._instance.buildTable()
            print("第一次创建CompatibleCRC32")
        return cls._instance

    def buildTable(self):
        self.PTI_TABLE = [0] * 256
        nData:int = 0
        nAccum:int = 0
        for i in range(0, 256):
            nData = i << 24
            nAccum = 0
            for j in range(0, 8):
                if 0 != ((nData ^ nAccum) & 0x80000000):
                    nAccum = (nAccum << 1) ^ self.CN
                else:
                    nAccum <<= 1
                nData <<= 1
            self.PTI_TABLE[i] = nAccum

def unsignedRightShitf(value: int, rightPos: int):
    """
    无符号Int右位移
    :param value: 需要位移的数值
    :param rightPos: 向右位移位数
    :return:
    """
    return (value >> rightPos) & 0x7FFFFFFF




def getCrcByBytes(datas:bytes):
    table: CompatibleCRC32Data = CompatibleCRC32Data()
    crc32: int = 0xFFFFFFFF
    if None == datas or len(datas) < 1:
        return crc32
    for i in range(0, len(datas)):
        data:int = datas[i]
        ur = unsignedRightShitf(crc32, 24)
        crc32 = (crc32 << 8) ^ table.PTI_TABLE[(ur) ^ (data & 0xFF)]
        crc32 = crc32 & 0xFFFFFFFF

    if crc32>INT_MAX:
        #实质为负数，python3的int最大值不是21亿，所以要用手段强制转为负数
        code:int = crc32 & 0x7FFFFFFF
        code = (~code) & 0x7FFFFFFF
        code = ~code
        return code

    return crc32

def get32BitDec(text:str):
    bs:bytes = bytes(text, "utf-8")
    return getCrcByBytes(bs)

def get32BitHex(text:str):
    dec:int = get32BitDec(text)
    sb:str = ""
    sb += HEX_MAP[(dec >> 28) & 0xF]
    sb += HEX_MAP[(dec >> 24) & 0xF]
    sb += HEX_MAP[(dec >> 20) & 0xF]
    sb += HEX_MAP[(dec >> 16) & 0xF]
    sb += HEX_MAP[(dec >> 12) & 0xF]
    sb += HEX_MAP[(dec >> 8) & 0xF]
    sb += HEX_MAP[(dec >> 4) & 0xF]
    sb += HEX_MAP[dec & 0xF]
    return sb

